//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package org_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas-org/api-server/api_common"
	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/org_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/user_dao"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/notices/notices_org"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/org_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *OrgApiImpl) CreateDepartMent(ctx context.Context, req *org_api.CreateDepartMentRequest) (*org_api.CreateDepartMentResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &org_api.CreateDepartMentResponse{
			Code:   org_api.CreateDepartMentResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}

	orgItem, err := org_dao.OrgInfoDao.Get(ctx, req.OrgId)
	if err != nil { //组织不存在
		return &org_api.CreateDepartMentResponse{
			Code:   org_api.CreateDepartMentResponse_CODE_NO_ORG,
			ErrMsg: "组织不存在",
		}, nil
	}
	if orgItem.OwnerUserId != sessionItem.UserId {
		return &org_api.CreateDepartMentResponse{
			Code:   org_api.CreateDepartMentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	//检查父部门是否存在
	if req.ParentDepartMentId != "" {
		exist, err := org_dao.DepartMentDao.Exist(ctx, req.OrgId, req.ParentDepartMentId)
		if err != nil {
			return nil, err
		}
		if !exist {
			return &org_api.CreateDepartMentResponse{
				Code:   org_api.CreateDepartMentResponse_CODE_NO_DEPART_MENT,
				ErrMsg: "目标部门不存在",
			}, nil
		}
	}

	departMentId := uuid.NewString()
	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		//创建部门
		err = org_dao.DepartMentDao.Insert(sessCtx, &org_dao.DepartMentInfoDbItem{
			DepartMentId:       departMentId,
			OrgId:              req.OrgId,
			DepartMentName:     req.DepartMentName,
			ParentDepartMentId: req.ParentDepartMentId,
			CreateTime:         nowTime,
			CreateUserId:       sessionItem.UserId,
			UpdateTime:         nowTime,
			SubDepartMentCount: 0,
			SubMemberCount:     0,
			EvaluateCount:      0,
		})
		if err != nil {
			return nil, err
		}
		if req.ParentDepartMentId != "" {
			//获取部门数量
			count, err := org_dao.DepartMentDao.CountSubDepartMent(sessCtx, req.OrgId, req.ParentDepartMentId)
			if err != nil {
				return nil, err
			}
			//更新部门数量
			err = org_dao.DepartMentDao.UpdateSubDepartMentCount(sessCtx, req.OrgId, req.ParentDepartMentId, count)
			if err != nil {
				return nil, err
			}
		}
		//更新组织计数
		count, err := org_dao.DepartMentDao.CountByOrg(sessCtx, req.OrgId)
		if err != nil {
			return nil, err
		}
		err = org_dao.OrgInfoDao.UpdateDepartMentCount(sessCtx, req.OrgId, count)
		if err != nil {
			return nil, err
		}
		return &org_api.CreateDepartMentResponse{
			Code:         org_api.CreateDepartMentResponse_CODE_OK,
			DepartMentId: departMentId,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToOrgScope(context.Background(), req.OrgId, &notices_org.CreateDepartMentNotice{
		OrgId:        req.OrgId,
		DepartMentId: departMentId,
	})
	if req.ParentDepartMentId != "" {
		go api_common.SendNoticeToOrgScope(context.Background(), req.OrgId, &notices_org.UpdateDepartMentNotice{
			OrgId:        req.OrgId,
			DepartMentId: req.ParentDepartMentId,
		})
	}
	return ret.(*org_api.CreateDepartMentResponse), nil
}

func (apiImpl *OrgApiImpl) UpdateDepartMent(ctx context.Context, req *org_api.UpdateDepartMentRequest) (*org_api.UpdateDepartMentResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &org_api.UpdateDepartMentResponse{
			Code:   org_api.UpdateDepartMentResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}

	orgItem, err := org_dao.OrgInfoDao.Get(ctx, req.OrgId)
	if err != nil { //组织不存在
		return &org_api.UpdateDepartMentResponse{
			Code:   org_api.UpdateDepartMentResponse_CODE_NO_ORG,
			ErrMsg: "组织不存在",
		}, nil
	}
	if orgItem.OwnerUserId != sessionItem.UserId {
		return &org_api.UpdateDepartMentResponse{
			Code:   org_api.UpdateDepartMentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	exist, err := org_dao.DepartMentDao.Exist(ctx, req.OrgId, req.DepartMentId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &org_api.UpdateDepartMentResponse{
			Code:   org_api.UpdateDepartMentResponse_CODE_NO_DEPART_MENT,
			ErrMsg: "部门不存在",
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = org_dao.DepartMentDao.UpdateName(sessCtx, req.OrgId, req.DepartMentId, req.DepartMentName, nowTime)
		if err != nil {
			return nil, err
		}
		return &org_api.UpdateDepartMentResponse{
			Code: org_api.UpdateDepartMentResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToOrgScope(context.Background(), req.OrgId, &notices_org.UpdateDepartMentNotice{
		OrgId:        req.OrgId,
		DepartMentId: req.DepartMentId,
	})
	return ret.(*org_api.UpdateDepartMentResponse), nil
}

func (apiImpl *OrgApiImpl) ListDepartMent(ctx context.Context, req *org_api.ListDepartMentRequest) (*org_api.ListDepartMentResponse, error) {
	emptyList := []*org_api.DepartMentInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &org_api.ListDepartMentResponse{
			Code:           org_api.ListDepartMentResponse_CODE_WRONG_SESSION,
			ErrMsg:         "会话不存在",
			DepartMentList: emptyList,
		}, nil
	}

	exist, err := org_dao.OrgInfoDao.Exist(ctx, req.OrgId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &org_api.ListDepartMentResponse{
			Code:           org_api.ListDepartMentResponse_CODE_NO_ORG,
			ErrMsg:         "组织不存在",
			DepartMentList: emptyList,
		}, nil
	}

	exist, err = org_dao.MemberDao.Exist(ctx, req.OrgId, sessionItem.UserId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &org_api.ListDepartMentResponse{
			Code:           org_api.ListDepartMentResponse_CODE_NO_PERMISSION,
			ErrMsg:         "没有权限",
			DepartMentList: emptyList,
		}, nil
	}

	departMentItemList, err := org_dao.DepartMentDao.ListByOrg(ctx, req.OrgId)
	if err != nil {
		return nil, err
	}
	//补充用户信息
	userIdList := []string{}
	for _, departmentItem := range departMentItemList {
		userIdList = append(userIdList, departmentItem.CreateUserId)
	}
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}
	//生成结果
	departMentList := []*org_api.DepartMentInfo{}
	for _, departmentItem := range departMentItemList {
		departMent := departmentItem.ToDepartMentInfo()
		createUser, ok := userItemMap[departmentItem.CreateUserId]
		if ok {
			departMent.CreateDisplayName = createUser.BasicInfo.DisplayName
			departMent.CreateLogoUri = createUser.BasicInfo.LogoUri
		}
		departMentList = append(departMentList, departMent)
	}
	return &org_api.ListDepartMentResponse{
		Code:           org_api.ListDepartMentResponse_CODE_OK,
		DepartMentList: departMentList,
	}, nil
}

func (apiImpl *OrgApiImpl) GetDepartMent(ctx context.Context, req *org_api.GetDepartMentRequest) (*org_api.GetDepartMentResponse, error) {
	emptyDepartMent := &org_api.DepartMentInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &org_api.GetDepartMentResponse{
			Code:           org_api.GetDepartMentResponse_CODE_WRONG_SESSION,
			ErrMsg:         "会话不存在",
			DepartMentInfo: emptyDepartMent,
		}, nil
	}

	exist, err := org_dao.OrgInfoDao.Exist(ctx, req.OrgId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &org_api.GetDepartMentResponse{
			Code:           org_api.GetDepartMentResponse_CODE_NO_ORG,
			ErrMsg:         "组织不存在",
			DepartMentInfo: emptyDepartMent,
		}, nil
	}

	exist, err = org_dao.MemberDao.Exist(ctx, req.OrgId, sessionItem.UserId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &org_api.GetDepartMentResponse{
			Code:           org_api.GetDepartMentResponse_CODE_NO_PERMISSION,
			ErrMsg:         "没有权限",
			DepartMentInfo: emptyDepartMent,
		}, nil
	}

	departMentItem, err := org_dao.DepartMentDao.Get(ctx, req.OrgId, req.DepartMentId)
	if err != nil {
		return &org_api.GetDepartMentResponse{
			Code:           org_api.GetDepartMentResponse_CODE_NO_DEPART_MENT,
			ErrMsg:         "部门不存在",
			DepartMentInfo: emptyDepartMent,
		}, nil
	}

	//补充用户信息
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, []string{departMentItem.CreateUserId})
	if err != nil {
		return nil, err
	}
	//生成结果
	departMent := departMentItem.ToDepartMentInfo()
	if len(userItemList) == 1 {
		departMent.CreateDisplayName = userItemList[0].BasicInfo.DisplayName
		departMent.CreateLogoUri = userItemList[0].BasicInfo.LogoUri
	}
	return &org_api.GetDepartMentResponse{
		Code:           org_api.GetDepartMentResponse_CODE_OK,
		DepartMentInfo: departMent,
	}, nil
}

func (apiImpl *OrgApiImpl) RemoveDepartMent(ctx context.Context, req *org_api.RemoveDepartMentRequest) (*org_api.RemoveDepartMentResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &org_api.RemoveDepartMentResponse{
			Code:   org_api.RemoveDepartMentResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}

	orgItem, err := org_dao.OrgInfoDao.Get(ctx, req.OrgId)
	if err != nil { //组织不存在
		return &org_api.RemoveDepartMentResponse{
			Code:   org_api.RemoveDepartMentResponse_CODE_NO_ORG,
			ErrMsg: "组织不存在",
		}, nil
	}
	if orgItem.OwnerUserId != sessionItem.UserId {
		return &org_api.RemoveDepartMentResponse{
			Code:   org_api.RemoveDepartMentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	departMentItem, err := org_dao.DepartMentDao.Get(ctx, req.OrgId, req.DepartMentId)
	if err != nil { //记录不存在
		return &org_api.RemoveDepartMentResponse{
			Code: org_api.RemoveDepartMentResponse_CODE_OK,
		}, nil
	}
	if departMentItem.SubDepartMentCount != 0 || departMentItem.SubMemberCount != 0 || departMentItem.EvaluateCount != 0 {
		return &org_api.RemoveDepartMentResponse{
			Code:   org_api.RemoveDepartMentResponse_CODE_HAS_SUB_ITEM,
			ErrMsg: "存在子部门/成员/评估",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = org_dao.DepartMentDao.Remove(sessCtx, req.OrgId, req.DepartMentId)
		if err != nil {
			return nil, err
		}
		if departMentItem.ParentDepartMentId != "" {
			count, err := org_dao.DepartMentDao.CountSubDepartMent(sessCtx, req.OrgId, departMentItem.ParentDepartMentId)
			if err != nil {
				return nil, err
			}
			err = org_dao.DepartMentDao.UpdateSubDepartMentCount(sessCtx, req.OrgId, departMentItem.ParentDepartMentId, count)
			if err != nil {
				return nil, err
			}
		}
		//更新组织计数
		count, err := org_dao.DepartMentDao.CountByOrg(sessCtx, req.OrgId)
		if err != nil {
			return nil, err
		}
		err = org_dao.OrgInfoDao.UpdateDepartMentCount(sessCtx, req.OrgId, count)
		if err != nil {
			return nil, err
		}
		return &org_api.RemoveDepartMentResponse{
			Code: org_api.RemoveDepartMentResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToOrgScope(context.Background(), req.OrgId, &notices_org.RemoveDepartMentNotice{
		OrgId:        req.OrgId,
		DepartMentId: req.DepartMentId,
	})
	if departMentItem.ParentDepartMentId != "" {
		go api_common.SendNoticeToOrgScope(context.Background(), req.OrgId, &notices_org.UpdateDepartMentNotice{
			OrgId:        req.OrgId,
			DepartMentId: departMentItem.ParentDepartMentId,
		})
	}
	return ret.(*org_api.RemoveDepartMentResponse), nil
}

func (apiImpl *OrgApiImpl) MoveDepartMent(ctx context.Context, req *org_api.MoveDepartMentRequest) (*org_api.MoveDepartMentResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &org_api.MoveDepartMentResponse{
			Code:   org_api.MoveDepartMentResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}

	orgItem, err := org_dao.OrgInfoDao.Get(ctx, req.OrgId)
	if err != nil { //组织不存在
		return &org_api.MoveDepartMentResponse{
			Code:   org_api.MoveDepartMentResponse_CODE_NO_ORG,
			ErrMsg: "组织不存在",
		}, nil
	}
	if orgItem.OwnerUserId != sessionItem.UserId {
		return &org_api.MoveDepartMentResponse{
			Code:   org_api.MoveDepartMentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	//检查是否路径回环
	departMentItemList, err := org_dao.DepartMentDao.ListByOrg(ctx, req.OrgId)
	if err != nil {
		return nil, err
	}
	departMentItemMap := map[string]*org_dao.DepartMentInfoDbItem{}
	for _, departMentItem := range departMentItemList {
		departMentItemMap[departMentItem.DepartMentId] = departMentItem
	}
	if req.ParentDepartMentId != "" {
		tmpDepartMentItem := departMentItemMap[req.ParentDepartMentId]
		for i := 0; i < 99; i++ { //放在死循环
			if tmpDepartMentItem == nil {
				return &org_api.MoveDepartMentResponse{
					Code:   org_api.MoveDepartMentResponse_CODE_NO_DEPART_MENT,
					ErrMsg: "目标部门不存在",
				}, nil
			}
			if tmpDepartMentItem.ParentDepartMentId == "" {
				break
			}
			if tmpDepartMentItem.DepartMentId == req.DepartMentId {
				return &org_api.MoveDepartMentResponse{
					Code:   org_api.MoveDepartMentResponse_CODE_NOT_ALLOW,
					ErrMsg: "无法移动到子部门",
				}, nil
			}
			tmpDepartMentItem = departMentItemMap[tmpDepartMentItem.ParentDepartMentId]
		}
	}
	curDepartMentItem := departMentItemMap[req.DepartMentId]
	if curDepartMentItem == nil {
		return &org_api.MoveDepartMentResponse{
			Code:   org_api.MoveDepartMentResponse_CODE_NO_DEPART_MENT,
			ErrMsg: "部门不存在",
		}, nil
	}
	if curDepartMentItem.ParentDepartMentId == req.ParentDepartMentId { //不需要移动
		return &org_api.MoveDepartMentResponse{
			Code: org_api.MoveDepartMentResponse_CODE_OK,
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		//更新父部门
		err = org_dao.DepartMentDao.UpdateParent(sessCtx, req.OrgId, req.DepartMentId, req.ParentDepartMentId, nowTime)
		if err != nil {
			return nil, err
		}
		if curDepartMentItem.ParentDepartMentId != "" {
			count, err := org_dao.DepartMentDao.CountSubDepartMent(sessCtx, req.OrgId, curDepartMentItem.ParentDepartMentId)
			if err != nil {
				return nil, err
			}
			err = org_dao.DepartMentDao.UpdateSubDepartMentCount(sessCtx, req.OrgId, curDepartMentItem.ParentDepartMentId, count)
			if err != nil {
				return nil, err
			}
		}
		if req.ParentDepartMentId != "" {
			count, err := org_dao.DepartMentDao.CountSubDepartMent(sessCtx, req.OrgId, req.ParentDepartMentId)
			if err != nil {
				return nil, err
			}
			err = org_dao.DepartMentDao.UpdateSubDepartMentCount(sessCtx, req.OrgId, req.ParentDepartMentId, count)
			if err != nil {
				return nil, err
			}
		}
		return &org_api.MoveDepartMentResponse{
			Code: org_api.MoveDepartMentResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToOrgScope(context.Background(), req.OrgId, &notices_org.UpdateDepartMentNotice{
		OrgId:        req.OrgId,
		DepartMentId: req.DepartMentId,
	})
	if curDepartMentItem.ParentDepartMentId != "" {
		go api_common.SendNoticeToOrgScope(context.Background(), req.OrgId, &notices_org.UpdateDepartMentNotice{
			OrgId:        req.OrgId,
			DepartMentId: curDepartMentItem.ParentDepartMentId,
		})
	}
	if req.ParentDepartMentId != "" {
		go api_common.SendNoticeToOrgScope(context.Background(), req.OrgId, &notices_org.UpdateDepartMentNotice{
			OrgId:        req.OrgId,
			DepartMentId: req.ParentDepartMentId,
		})
	}
	return ret.(*org_api.MoveDepartMentResponse), nil
}
